package com.xbongbong.pro.statistic.abstracts;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.errorcodes.BiErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartDtoHelp;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.DrillFieldEnum;
import com.xbongbong.pro.statistic.enums.StatisticsTypeEnum;
import com.xbongbong.pro.statistic.help.ChartResultHelp;
import com.xbongbong.pro.statistic.help.CustomHelp;
import com.xbongbong.pro.statistic.interfaces.ChartResultBase;
import com.xbongbong.pro.statistic.model.ChartCustomModel;
import com.xbongbong.pro.statistic.pojo.ChartParamPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.DrillResultChartFieldInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.DrillResultChartInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.DrillResultPojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartPenetrateResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultVO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.sys.domain.entity.UserEntity;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author zyy
 * @date 2022/10/14/ 13:50:00
 * @since v1.0
 */
public abstract class AbstractChartResultBase implements ChartResultBase {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractChartResultBase.class);
    @Resource
    private ChartResultHelp chartResultHelp;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private ChartCustomModel chartCustomModel;
    @Resource
    private ChartDtoHelp chartDtoHelp;
    @Resource
    private CustomHelp customHelp;

    /**
     * 处理请求参数
     *
     * @param chartResultDTO 请求入参实体
     * @return com.xbongbong.pro.bi.commons.pojo.ChartParamPojo
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public ChartParamPojo dealChartParam(ChartResultDTO chartResultDTO) throws XbbException {
        //同时查询系统、自定义图表
        List<ChartEntity> list = chartResultHelp.chartEntityListFactory(StatisticsTypeEnum.ALL,chartResultDTO);
        //初始化 chartResultPojo
        ChartResultPojo chartResultPojo = chartResultHelp.initChartResultPojo(chartResultDTO);
        DrillResultPojo drillResultPojo = customHelp.formatDrillMap(chartResultDTO.getCorpid(), chartResultDTO, list);
        chartResultPojo.setDrillResultPojo(drillResultPojo);
        return new ChartParamPojo(list,chartResultPojo);
    }

    /**
     * 图表结果解析
     *
     * @param chartResultDTO 请求入参实体
     * @param chartParamPojo 入参解析后的实体
     * @param chartList 图表解析数据数组
     * @param chartMap 图表与图表统计数据的映射容器
     * @param errors 错误码数组
     * @param explainEntityList 图表字段解释数组
     * @param chartResultVO 图表统计数据响应vo
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public void chartAnalysis(ChartResultDTO chartResultDTO,ChartParamPojo chartParamPojo,List<ChartResultDetailVO> chartList ,Map<String, Object> chartMap,List<JSONObject> errors,List<PaasFormExplainEntity> explainEntityList,ChartResultVO chartResultVO) throws XbbException {
        List<ChartEntity> list = chartParamPojo.getChartEntityList();
        ChartResultPojo chartResultPojo = chartParamPojo.getChartResultPojo();
        String corpid = chartResultDTO.getCorpid();
        boolean bigData = commonHelp.checkBlacklistBigDataCorp(corpid);
        //根据查询出的解释信息，更新list中的属性
        for (ChartEntity chartEntity : list) {
            // 防止单位转换时前一个指标对下一个指标产生影响,因为这个循环中使用的是同一个chartResultPojo
            chartResultPojo.setNumFormatFlag(null);
            //查询单个报表数据
            ChartResultDetailVO chartResultDetailVO = null;
            try {
                //预留特殊校验
                filterByDriverSource(chartResultDTO,chartParamPojo,chartEntity);
                chartResultHelp.putChartResultPojoOfChart(chartResultPojo,chartEntity);
                if (bigData) {
                    //公司数据大的不计算统计结果
                    chartResultDetailVO = new ChartResultDetailVO();
                } else {
                    //图表联动入参解析
                    chartResultHelp.analysisLinkage(chartResultDTO,chartEntity,explainEntityList);
                    chartResultHelp.charTypeFilter(chartResultDTO,chartEntity,explainEntityList);
                    chartResultDetailVO = getDiyResult(chartEntity, chartResultPojo, explainEntityList, chartResultDTO.getSearch(),Boolean.FALSE);
                }

                if (chartResultDetailVO == null) {
                    chartResultDetailVO = new ChartResultDetailVO();
                }

                //联动渲染时需要将联动入参返回
                if(!chartResultHelp.linkParamFilter(chartResultDTO.getLinkage())){
                    chartResultDetailVO.setLinkage(chartResultDTO.getLinkage());
                }

                //导出功能中需要判断统计
                if (chartEntity.getRowGroupAttr() != null) {
                    chartResultDetailVO.setGroupSize(chartEntity.getRowGroupAttr().size());
                }
                chartList.add(chartResultDetailVO);
                String key = String.format(SymbolConstant.UNDERLINE_PLACE, chartEntity.getStatisticsType(), chartEntity.getId());
                chartMap.put(key, chartResultDetailVO);
            } catch (XbbException e) {
                if (Objects.equals(BiErrorCodeEnum.API_ERROR_241013.getCode(), e.getCode())) {
                    chartResultVO.addWaitIdIn(chartEntity.getId());
                    LOG.error(chartEntity.getId() + e.getMsg(), e);
                }else {
                    JSONObject errorJson = new JSONObject();
                    errorJson.put(chartEntity.getId().toString(),e.getMsg());
                    errors.add(errorJson);
                    chartResultVO.setErrors(errors);
                    LOG.error("chartResult方法中数据获取报错，chartID=" + chartEntity.getId(), e);
                }
            } catch (Exception e) {
                JSONObject errorJson = new JSONObject();
                errorJson.put(chartEntity.getId().toString(), BiErrorCodeEnum.API_ERROR_241021.getMsg());
                errors.add(errorJson);
                chartResultVO.setErrors(errors);
                LOG.error("chartResult方法中数据获取报错，chartID=" + chartEntity.getId(), e);
            }
        }
    }
    /**
     * 图表结果处理器
     *
     * @param chartResultDTO 请求入参实体
     * @param chartParamPojo 入参解析后的实体
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultVO
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public ChartResultVO chartResultHandle(ChartResultDTO chartResultDTO,ChartParamPojo chartParamPojo) throws XbbException {
        List<ChartResultDetailVO> chartList = new ArrayList<>();
        //statisticsType_图表id---图表信息
        Map<String, Object> chartMap = new HashMap<>(chartParamPojo.getChartEntityList().size());
        List<JSONObject> errors = new ArrayList<>();
        ChartResultVO chartResultVO = new ChartResultVO();
        String corpid = chartResultDTO.getCorpid();
        List<PaasFormExplainEntity> explainEntityList = chartResultHelp.getExplainList4Chart(false, chartParamPojo.getChartEntityList(), corpid, chartParamPojo.getChartResultPojo().getDrillResultPojo());

        chartAnalysis(chartResultDTO, chartParamPojo, chartList, chartMap, errors, explainEntityList, chartResultVO);

        List<ChartResultDetailVO> sortList = chartResultHelp.sortChartList(chartResultDTO, chartMap, chartList);
        chartResultVO.setChartList(sortList);
        return chartResultVO;
    }

    @Override
    public ChartResultVO getChartResult(ChartResultDTO chartResultDTO) throws XbbException {
        return chartResultHandle(chartResultDTO,dealChartParam(chartResultDTO));
    }

    /**
     * 预留不同数据源图表的特殊校验
     *
     * @param chartResultDTO 入参请求实体
     * @param chartParamPojo 入参解析后的实体对象
     * @param chartEntity 图表实体
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public abstract void filterByDriverSource(ChartResultDTO chartResultDTO,ChartParamPojo chartParamPojo,ChartEntity chartEntity) throws XbbException;

    /**
     * 预留方法-获取图表统计数据
     *
     * @param chartEntity 图表实体
     * @param chartResultPojo 入参解析后的实体对象
     * @param explainEntityList 图表字段解释数组
     * @param search 查询条件
     * @param penetrateFlag 是否穿透业务调用 true-是，false-否
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public abstract ChartResultDetailVO getDiyResult(ChartEntity chartEntity, ChartResultPojo chartResultPojo, List<PaasFormExplainEntity> explainEntityList, List<JSONObject> search,boolean penetrateFlag) throws XbbException;


    /**
     * 获取自定义图表穿透
     *
     * @param chartResultDTO
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultVO
     * @author zyy
     * @date 2022/10/28
     * @version v1.0
     */
    public ChartResultVO chartPenetrateResult(ChartPenetrateResultDTO chartResultDTO) throws XbbException{
        //入参转换为数据库的查询条件
        Map<String, Object> map = BeanUtil.convertBean2Map(chartResultDTO, true);
        List<ChartEntity> list = chartCustomModel.findEntitys(map);
        if (CollectionUtils.isEmpty(list)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }

        //处理入参并封装chartResultPojo
        UserEntity userEntity = BeanUtil.copyProperties(chartResultDTO.getLoginUser(), UserEntity.class, false);
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4SystemFull(userEntity, chartResultDTO);
        // 穿透这边id是放在idIn参数里面的，但是钻取使用的时候customIdIn判断的，所以这样前置处理
        List<Long> customIdIn = chartResultDTO.getCustomIdIn();
        if (CollectionUtils.isEmpty(customIdIn)) {
            chartResultDTO.setCustomIdIn(chartResultDTO.getIdIn());
        } else {
            customIdIn.addAll(chartResultDTO.getIdIn());
        }
        DrillResultPojo drillResultPojo = customHelp.formatDrillMap(chartResultDTO.getCorpid(), chartResultDTO, list);
        chartResultPojo.setDrillResultPojo(drillResultPojo);
        //获取图表的explain
        List<PaasFormExplainEntity> explainEntityList = chartResultHelp.getExplainList4Chart(true, list, chartResultDTO.getCorpid(), drillResultPojo);
        //处理图表-业务的映射关系
        Map<Long, Integer> formIdToBusinessTypeMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(Objects.equals(XbbRefTypeEnum.CONTRACT_PERFORMANCE.getCode(),list.get(0).getDriverSources().getIntValue(StringConstant.BUSINESS_TYPE))){
            formIdToBusinessTypeMap.put(list.get(0).getDriverSources().getLongValue(StringConstant.FORM_ID),XbbRefTypeEnum.CONTRACT_PERFORMANCE.getCode());
        }else {
            explainEntityList.forEach(e -> formIdToBusinessTypeMap.put(e.getFormId(), e.getBusinessType()));
        }

        //获取穿透数据
        List<ChartResultDetailVO> chartList = getChartPenetrateResult(chartResultDTO, list, chartResultPojo, explainEntityList, formIdToBusinessTypeMap);

        ChartResultVO chartResultVO = new ChartResultVO();
        chartResultVO.setChartList(chartList);
        return chartResultVO;
    }

    /**
     * 获取穿透数据
     *
     * @param chartResultDTO 原始的入参实体
     * @param list 图表数组
     * @param chartResultPojo 处理后的入参实体
     * @param explainEntityList 图表explain实体数组
     * @param formIdToBusinessTypeMap  formId ： businessType
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO
     * @author zyy
     * @date 2022/10/28
     * @version v1.0
     */
    private List<ChartResultDetailVO> getChartPenetrateResult(ChartPenetrateResultDTO chartResultDTO, List<ChartEntity> list, ChartResultPojo chartResultPojo, List<PaasFormExplainEntity> explainEntityList, Map<Long, Integer> formIdToBusinessTypeMap) throws XbbException {
        List<ChartResultDetailVO> chartList = new ArrayList<>();
        for (ChartEntity chartEntity : list) {
            Integer chartType = chartEntity.getChartType();
            //穿透默认复用查询表的逻辑，因此这里手动设置图表类型
            chartEntity.setChartType(ChartTypeEnum.DATA_QUERY_TABLE.getCode());
            chartEntity.setName(ChartTypeEnum.DATA_QUERY_TABLE.getName());
            //检测数据安全
            if (!chartResultHelp.checkDataSecurity(chartType, chartResultDTO)) {
                break;
            }

            //获取表头
            JSONArray disArray = new JSONArray();
            JSONArray penetrateArray = chartEntity.getPenetrateAttr();
            if (penetrateArray != null && penetrateArray.size() > 0) {
                disArray = penetrateArray;
                chartEntity.setDisplayAttr(disArray);
            } else {
                if (chartType.equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())) {
                    // 获取没有设置穿透显示字段时的穿透点击的那个表头字段
                    JSONObject clickField = chartResultHelp.getPenetrateClickField(chartResultDTO, chartEntity);
                    if (!Objects.isNull(clickField)) {
                        disArray.add(clickField);
                    }
                } else {
                    // 对于没设置穿透展示字段的统计图是需要需要分类和系列的
                    disArray.addAll(chartEntity.getChartClassify());
                    disArray.addAll(chartEntity.getChartSeries());
                }
                chartResultHelp.dealDisplayAttrTimeFormat(disArray, chartEntity, chartResultDTO);
                chartEntity.setDisplayAttr(disArray);
            }
            chartResultPojo.setChartEntity(chartEntity);

            //解析穿透时的限制条件
            JSONArray filterArray = chartEntity.getFilter();
            List<JSONObject> filterList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(filterArray)) {
                filterList = filterArray.toJavaList(JSONObject.class);
            }
            if (chartType.equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())) {
                //统计表穿透数据解析
                chartResultHelp.parseTableCondition(chartResultDTO.getPenetrateCondition(), filterList, formIdToBusinessTypeMap,StringConstant.PENETRATE_FLAG);
            } else {
                // 图穿透时x,y轴的字段解析（处理图的穿透时候的参数，创建filter）
                chartResultHelp.updateChartClassifyAndSeries(chartResultPojo, chartEntity);
                //统计图穿透数据解析
                chartResultHelp.parseChartCondition(chartResultDTO.getSelectedAxis(),chartResultDTO.getSelectedLegend(),chartEntity,filterList,StringConstant.PENETRATE_FLAG);
            }
            chartEntity.setFilter(JSONArray.parseArray(filterList.toString()));
            //处理联动条件
            chartResultHelp.analysisLinkage(chartResultDTO,chartEntity,explainEntityList);
            // 自定义图表的穿透实际上走的是查询表的逻辑，因此这里直接复用图表result的抽象方法
            chartList.add(getDiyResult(chartEntity, chartResultPojo, explainEntityList, chartResultDTO.getSearch(),Boolean.TRUE));
        }
        return chartList;
    }

}
